package simplevideochat.application.drawingdesk
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Graphics;
	import flash.display.IBitmapDrawable;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import mx.core.UIComponent;
	import simplevideochat.communication.connection.ConnectionEvent;
	import simplevideochat.communication.connection.ConnectionEventData;
	import simplevideochat.communication.connection.IConnection;
	import mx.events.FlexEvent;
	
	/**
	 * Класс доски для рисования
	 * @author Alexey Ustinov
	 */
	public class DrawingDesk 
	{	
		static public const PEN:String = "pen";
		static public const ERASER:String = "eraser";
		
		private var _isPen:Boolean;
		private var _isEraser:Boolean;
		private var _color:uint;
		private var _thickness:uint;
		private var _currentTool:String;
		private var currentLinePoints:Vector.<Point>;
		private var isMouseDown:Boolean;
		private var connection:IConnection;
		private var _paintingComponent:IPaintingComponent;
		private var currentBitmap:BitmapData;
		private var pen_color:uint;
		
		/**
		 * Конструктор класс доски для рисования
		 */
		public function DrawingDesk() 
		{
			isPen = true;
			isEraser = false;
			color = 0x000000;
			pen_color = color;
			thickness = 1;
			currentTool = DrawingDesk.PEN;
			
			currentLinePoints = new Vector.<Point>();
			
			isMouseDown = false;
		}
		
		/**
		 * Обновить графическое содержимое доски для рисования
		 */
		public function update():void
		{
			paintingComponent.graphics.beginBitmapFill(currentBitmap, null, false);
			paintingComponent.graphics.drawRect(0, 0, paintingComponent.width, paintingComponent.height);
			paintingComponent.graphics.endFill();
			paintingComponent.graphics.lineStyle(thickness, color);
		}
		
		/**
		 * Очистить содержимое доски для рисования
		 */
		public function clear():void
		{
			_clear();
			var msg:DrawingDeskConnectionData = new DrawingDeskConnectionData(simplevideochat.application.drawingdesk.DrawingDeskConnectionData.CLEAR_ALL_EVENT);
			connection.sendMessage(msg);
		}
		
		/**
		 * Прикрепить объект подключения к доске для рисования
		 * @param	connection	Объект подключения
		 */
		public function attachConnection(connection:IConnection):void
		{
			this.connection = connection;
			this.connection.addEventListener(DrawingDeskConnectionData.DRAW_EVENT, deskDrawHandler);
			this.connection.addEventListener(DrawingDeskConnectionData.CLEAR_ALL_EVENT, deskClearAllHandler);
		}
		
			
		/*
		 *--------------------------------------------------------------------- 
		 * Private
		 *--------------------------------------------------------------------- 
		 */
		
		 /**
		  * Очистить рабочую область
		  */
		private function _clear():void
		{
			paintingComponent.update();
			currentBitmap = new BitmapData(paintingComponent.width, paintingComponent.height);
			currentBitmap.draw(paintingComponent as IBitmapDrawable);
			update();
		}
		
		/**
		 * Обработчик события нажатия левой кнопки мыши
		 * @param	e	Событие нажатия левой кнопки мыши
		 */
		private function mouseDownHandler(e:MouseEvent):void
		{
			beginPaint();
			paintingComponent.graphics.moveTo(e.localX, e.localY);
			paintingComponent.graphics.lineTo(e.localX + 1, e.localY + 1);
			currentLinePoints.push(new Point(e.localX, e.localY));
			currentLinePoints.push(new Point(e.localX + 1, e.localY + 1));
		}
		
		/**
		 * Обработчик события перемещения мыши над paintComponent
		 * @param	e	Событие перемещения мыши
		 */
		private function mouseMoveHandler(e:MouseEvent):void 
		{
			if (isMouseDown) {
				paintingComponent.graphics.lineTo(e.localX, e.localY);
				currentLinePoints.push(new Point(e.localX, e.localY));
			}
		}
		
		/**
		 * Обработчик события отпускания левой кнопки мыши
		 * @param	e	Событие отпускания левой кнопки мыши
		 */
		private function mouseUpHandler(e:MouseEvent):void 
		{
			endPaint();
		}
		
		/**
		 * Обработчик события перемещения мыши за пределы paintComponent
		 * @param	e	Событие перемещения мыши за пределы
		 */
		private function mouseOutHandler(e:MouseEvent):void 
		{
			endPaint();
		}
		
		/**
		 * Начать рисование линии
		 */
		private function beginPaint():void
		{
			isMouseDown = true;
			currentLinePoints = new Vector.<Point>();
			paintingComponent.graphics.lineStyle(thickness, color);
		}
		
		/**
		 * Закончить рисование линии
		 */
		private function endPaint():void
		{
			if (isMouseDown) {
				isMouseDown = false;
				
				if (connection) {
					sendDrawMessage();
				}
			}
			
			saveState();
		}
		
		/**
		 * Отправить сообщение
		 */
		private function sendDrawMessage():void
		{
			var msg:DrawingDeskConnectionData = new DrawingDeskConnectionData(DrawingDeskConnectionData.DRAW_EVENT, currentLinePoints, color, thickness);
			connection.sendMessage(msg);
		}
		
		/**
		 * Обработчик события получения графических данных от собеседников
		 * @param	event	Событие получения графических данных
		 */
		private function deskDrawHandler(event:ConnectionEvent):void
		{
			trace("DrawingDesk: get draw event");
			var data:DrawingDeskConnectionData = DrawingDeskConnectionData.parseFromObject(event.connectionData);
			if (data) {
				//TODO рисование в буфер
				paintingComponent.graphics.lineStyle(data.thickness, data.color);
				paintingComponent.graphics.moveTo(data.points[0].x, data.points[0].y);
				for each(var point:Point in data.points)
				{
					paintingComponent.graphics.lineTo(point.x, point.y);
				}
				paintingComponent.graphics.lineStyle(thickness, color);
				
				saveState();			
			}
		}
		
		/**
		 * Обработчик события очистки рабочей области
		 * @param	event	Событие очистки рабочей области
		 */
		private function deskClearAllHandler(event:ConnectionEvent):void
		{
			trace("DrawingDesk: get clear all event");
			_clear();
		}
		
		/**
		 * Сохранить состояние рабочей области
		 */
		private function saveState():void
		{
			currentBitmap = new BitmapData(currentBitmap.width, currentBitmap.height)
			currentBitmap.draw(paintingComponent as IBitmapDrawable);
		}
		
		
		/*
		 *---------------------------------------------------------------------
		 * Getters/Setters
		 *---------------------------------------------------------------------
		 */
		
		public function get isPen():Boolean 
		{
			return _isPen;
		}
		
		[Bindable]
		public function set isPen(value:Boolean):void 
		{
			_isPen = value;
		}
		
		public function get isEraser():Boolean 
		{
			return _isEraser;
		}
		
		[Bindable]
		public function set isEraser(value:Boolean):void 
		{
			_isEraser = value;
		}
		
		public function get thickness():uint 
		{
			return _thickness;
		}
		
		[Bindable]
		public function set thickness(value:uint):void 
		{
			_thickness = value;
		}
		
		public function get currentTool():String 
		{
			return _currentTool;
		}
		
		public function set currentTool(value:String):void 
		{
			if (value == DrawingDesk.PEN) {
				isPen = true;
				isEraser = false;
				color = pen_color;
			} else {
				isEraser = true;
				isPen = false;
				pen_color = color;
				color = 0xffffff;
			}
			_currentTool = value;
		}
		
		public function get color():uint 
		{
			return _color;
		}
		
		[Bindable]
		public function set color(value:uint):void 
		{
			_color = value;
		}
		
		public function get paintingComponent():IPaintingComponent
		{
			return _paintingComponent;
		}
		
		[Bindable]
		public function set paintingComponent(value:IPaintingComponent):void 
		{
			_paintingComponent = value;
			if (value != null) {
				paintingComponent.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
				paintingComponent.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
				paintingComponent.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
				paintingComponent.addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);	
				currentBitmap = new BitmapData(paintingComponent.width, paintingComponent.height, false);
			}
		}
		
		
	}

}